home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickTime / Sample Code / QuickTime™ codec example / examplecodec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-26  |  49.9 KB  |  1,798 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        examplecodec.c
  3.  
  4.     Copyright:    © 1991-1996 by Apple Computer, Inc., all rights reserved.
  5.  
  6.     This is an example of am image compression codec that handles both
  7.     compression and decompression of images as passed to it by the 
  8.     Image Compression manager. It is built as a Component Manager Component.
  9.  
  10.     The compression scheme here is 420 YUV. The image is stored as separate 
  11.     luminance and chrominance channels. For each 2x2 block of pixels in the
  12.     source image we store 4 luminance (Y) components, 1 Y-Red component (U) and
  13.     1 Y-Blue (V) component. Each Y-component is stored as 6-bits,  resulting in a 
  14.     savings of 2.4:1 over a 24-bit/pixel image (6*4 + 2*8)/4 = 10 bits/pixel.
  15.  
  16. */
  17.  
  18. #include <Memory.h>
  19. #include <Resources.h>
  20. #include <Quickdraw.h>    
  21. #include <QDOffscreen.h>
  22. #include <OSUtils.h>
  23. #include <Errors.h>
  24. #include <FixMath.h>
  25.  
  26. #include "ImageCodec.h"
  27.  
  28. #ifndef _CreateRoutineDescriptor_
  29. #define _CreateRoutineDescriptor_
  30. #if GENERATINGPOWERPC
  31.     #define ExternRoutineDescriptor(info, proc)                                    \
  32.      extern RoutineDescriptor g##proc##RD;
  33.     
  34.     #define CreateRoutineDescriptor(info, proc)                                    \
  35.      RoutineDescriptor g##proc##RD = BUILD_ROUTINE_DESCRIPTOR(info, proc);
  36.     
  37.     #define GetRoutineAddress(proc)    (&g##proc##RD)
  38. #else
  39.     #define ExternRoutineDescriptor(info, proc)
  40.     #define CreateRoutineDescriptor(info, proc)
  41.  
  42.     #define GetRoutineAddress(proc)    (proc)
  43. #endif
  44. #endif
  45.  
  46.  
  47. #ifdef    POWERPC_NATIVE
  48.     #pragma    options align=mac68k
  49. #endif
  50.  
  51. #ifndef NOASM
  52.     #define NOASM 0
  53. #endif
  54.  
  55. #ifndef DECO_BUILD
  56.     #define DECO_BUILD 0
  57. #endif
  58.  
  59. #ifndef COMP_BUILD
  60.     #define COMP_BUILD 0
  61. #endif
  62.  
  63. #if !DECO_BUILD && !COMP_BUILD
  64.     #error "must specify either DECO_BUILD or COMP_BUILD"
  65. #endif
  66.  
  67. #if DECO_BUILD && !defined(ASYNC_DECODE)
  68.     #define ASYNC_DECODE 1            // if defined, use scheduled asynchronous display
  69. #endif
  70.  
  71. #ifndef ASYNC_DECODE
  72.     #define ASYNC_DECODE 0
  73. #endif
  74.  
  75. #if !defined(QT_MP) && ASYNC_DECODE && defined(POWERPC_NATIVE)
  76.     #define QT_MP 1
  77. #endif
  78.  
  79. #ifndef QT_MP
  80.     #define QT_MP 0
  81. #endif
  82.  
  83. #if QT_MP && !ASYNC_DECODE
  84.     #error "can't QT_MP without ASYNC_DECODE"
  85. #endif
  86.  
  87. /* Version information */
  88.  
  89. #define    EXAMPLE_CODEC_REV            2
  90. #define    codecInterfaceVersion        2                /* high word returned in component GetVersion */
  91.  
  92.  
  93.  
  94. /* Some useful macros and constants */
  95.  
  96. #define    R_W    0x4ccd
  97. #define    G_W    0x970a
  98. #define    B_W    0x1c29
  99. #define    PIN(_n)        ((_n) < 0 ? 0 : (_n) > 255 ? 255 : (_n))
  100.  
  101.  
  102. /*
  103.     Our data structure declarations
  104. */
  105.  
  106. #if DECO_BUILD
  107.  
  108. #define QUEUE_SIZE 30
  109.  
  110. #ifndef fieldOffset
  111.     #define fieldOffset(type, field) ((short) &((type *) 0)->field)
  112. #endif
  113.  
  114. /*
  115.     The DecompressRecord is used to store the information needed
  116.     to decompress a frame asynchronously.
  117. */
  118. struct DecompressRecord {
  119.     ComponentMPWorkFunctionHeaderRecord    header;
  120.     void *nextBusy;            // next DecompressRecord that is queued up
  121.     void *nextFree;            // next unused DecompressRecord
  122.     Ptr srcData;            // pointer to compressed data
  123.     Ptr baseAddr;            // base address of destination PixMap
  124.     short rowBytes;            // rowBytes parameter of dest PixMap
  125.     short width;            // width (in pixels) of a row
  126.     short numStrips;        // number of strips to draw
  127.     long srcDataIncrement;    // increment for srcData between strips
  128.     long baseAddrIncrement;    // increment for baseAddr between strips
  129.     Boolean shieldCursor;    // if we need to shield the cursor
  130.     Boolean inQueue;
  131.     ICMCompletionProcRecord completionProc;    // completion proc record to call when done
  132.     TimeValue frameTime;    // what time to decompress this frame
  133.     Fixed rate;                // rate of movie
  134.     long scale;                // time scale
  135.     struct Globals *glob;    // pointer to our globals
  136. };
  137. typedef struct DecompressRecord DecompressRecord;
  138.  
  139. #endif
  140.  
  141. /* This is the structure we use to hold data used by all instances of
  142.    this compressor and decompressor */
  143.  
  144. typedef struct    {                    
  145.     Handle    rgbwTable;                    /* optional encode/decode table */
  146.     Handle    giwTable;                    /* another optional encode/decode table */
  147.     CodecInfo    **info;                    /* our cached codec info structure */
  148. } SharedGlobals;
  149.  
  150.  
  151. /* This is the structure we use to store our global data for each instance */
  152.  
  153. typedef struct    {                        
  154.     SharedGlobals    *sharedGlob;        /* pointer to instance-shared globals */
  155. #if ASYNC_DECODE
  156.     QTCallBack            callBack;                // our call back
  157.     QTCallBackUPP        decompressCallBackUPP;    // pointer to our decompress callback
  158.     ImageSequence        sequenceID;
  159.     QHdr                busyQueueHead;            // queue header for queued decompress records
  160.     QHdr                freeQueueHead;            // queue header for free decompress records
  161.     DecompressRecord    queue[QUEUE_SIZE];        // for queued frames
  162.     long                a5World;                // A5 world for decompress callback
  163.     Boolean                queueIsRunning;            // set if decompress queue is currently running
  164.     ComponentInstance    target;
  165.     volatile short        decompressCount;        // keep track of frames being decompressed/compressed (should only ever hit 1)
  166.  
  167.     ComponentMPWorkFunctionUPP
  168.                         decompressFunction;
  169.     void                *decompressFunctionRefCon;
  170. #endif
  171. } Globals;
  172.  
  173.  
  174. #define IMAGECODEC_BASENAME() CD
  175. #define IMAGECODEC_GLOBALS() Globals *storage
  176.  
  177. #define CALLCOMPONENT_BASENAME IMAGECODEC_BASENAME
  178. #define CALLCOMPONENT_GLOBALS IMAGECODEC_GLOBALS
  179.  
  180. #include "ImageCodec.k.h"
  181. #include "Components.k.h"
  182.  
  183.  
  184.  
  185. /* Function prototypes to keep the compiler smiling. */
  186.  
  187. #if QT_MP
  188.     Boolean TestBusy( Globals *glob );
  189. #endif
  190.  
  191. #if COMP_BUILD
  192. pascal void
  193. CompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
  194. #endif
  195.  
  196. #if DECO_BUILD
  197. pascal void
  198. DecompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
  199. #endif
  200.  
  201. ComponentResult
  202. InitSharedTables(Globals *glob,ComponentInstance self);
  203.  
  204. #if ASYNC_DECODE
  205. pascal ComponentResult DecompressWorkFunction(Globals *glob, DecompressRecord *drp);
  206.  
  207. CreateRoutineDescriptor(uppComponentMPWorkFunctionProcInfo, DecompressWorkFunction)
  208.  
  209. pascal void DecompressCallBack(QTCallBack cb,long refcon);
  210.     
  211. CreateRoutineDescriptor(uppQTCallBackProcInfo, DecompressCallBack)
  212. #endif
  213.  
  214.  
  215. /************************************************************************************ 
  216.  *    This is the main dispatcher for our codec. All calls from the codec manager
  217.  *    will come through here, with a unique selector and corresponding parameter block.
  218.  *
  219.  *    This routine must be first in the code segment of the codec component.
  220.  */
  221.  
  222. pascal ComponentResult CDComponentDispatch(ComponentParameters *params, Globals *storage);
  223.  
  224. #ifdef POWERPC_NATIVE
  225. struct RoutineDescriptor CDComponentDispatchRD =
  226.           BUILD_ROUTINE_DESCRIPTOR((kPascalStackBased | RESULT_SIZE (kFourByteCode) |
  227.                             STACK_ROUTINE_PARAMETER (1, kFourByteCode) |
  228.                             STACK_ROUTINE_PARAMETER (2, kFourByteCode)),CDComponentDispatch);
  229. #endif
  230.  
  231. static ProcPtr CDFindRoutineProcPtr(short selector, ProcInfoType *procInfo);
  232.  
  233. pascal ComponentResult CDComponentDispatch(ComponentParameters *params, Globals *storage)
  234. {
  235.     ProcPtr theProc;
  236.     ProcInfoType theProcInfo;
  237.     ComponentResult result = codecUnimpErr;
  238.  
  239.      theProc = CDFindRoutineProcPtr(params->what, &theProcInfo);
  240.     if (theProc) 
  241.         result = CallComponentFunctionWithStorageProcInfo((Handle)storage, params, theProc, theProcInfo);
  242.  
  243.     return result;
  244. }
  245.  
  246. static ProcPtr CDFindRoutineProcPtr(short selector, ProcInfoType *procInfo)
  247. {
  248.     ProcPtr aProc;
  249.     ProcInfoType pi;
  250.  
  251. #define ComponentCall(a)    case kComponent##a##Select:  aProc = (ProcPtr)CD##a; pi = uppCallComponent##a##ProcInfo; break;
  252. #define CodecCall(a)        case kImageCodec##a##Select: aProc = (ProcPtr)CD##a; pi = uppImageCodec##a##ProcInfo; break;
  253. #if COMP_BUILD
  254. #define CompressCall(a)        CodecCall(a)
  255. #define DecompressCall(a)
  256. #endif
  257. #if DECO_BUILD
  258. #define CompressCall(a)
  259. #define DecompressCall(a)    CodecCall(a)
  260. #endif
  261.  
  262. #define ComponentError(a)
  263. #define DecompressError(a)
  264. #define CompressError(a)
  265.  
  266.  
  267.     switch (selector) {
  268.         /* the multiprocessor stuff will explode if called from 68K ... so don't let the 
  269.             MP INIT think that this code supports MP */
  270.     #if ASYNC_DECODE && QT_MP
  271.         ComponentCall    (GetMPWorkFunction)
  272.     #else
  273.         ComponentError    (GetMPWorkFunction)
  274.     #endif
  275.         ComponentError    (Unregister)
  276.     #if ASYNC_DECODE && QT_MP
  277.         ComponentCall    (Target)
  278.     #else
  279.         ComponentError    (Target)
  280.     #endif
  281.         ComponentError    (Register)
  282.         ComponentCall    (Version)
  283.         ComponentCall    (CanDo)
  284.         ComponentCall    (Close)
  285.         ComponentCall    (Open)
  286.  
  287.         CodecCall        (GetCodecInfo)
  288.         
  289.         CompressCall    (GetCompressionTime)
  290.         CompressCall    (GetMaxCompressionSize)
  291.         CompressCall    (PreCompress)
  292.         CompressCall    (BandCompress)
  293.         DecompressCall    (PreDecompress)
  294.         
  295.         DecompressCall    (BandDecompress)
  296.         CodecCall        (Busy)
  297.         DecompressCall    (GetCompressedImageSize)
  298.         DecompressError    (GetSimilarity)
  299.         DecompressCall    (TrimImage)
  300.     
  301.         CompressError    (RequestSettings)
  302.         CompressError    (GetSettings)
  303.         CompressError    (SetSettings)
  304.     #if ASYNC_DECODE
  305.         DecompressCall    (Flush)
  306.     #endif
  307.         ComponentError    (SetTimeCode)
  308.     
  309.         DecompressError    (IsImageDescriptionEquivalent)
  310.         ComponentError    (NewMemory)
  311.         ComponentError    (DisposeMemory)
  312.         DecompressError    (HitTestData)
  313.         ComponentError    (NewImageBufferMemory)
  314.         
  315.         DecompressError    (ExtractAndCombineFields)
  316.         
  317.         default:
  318.             aProc = nil;
  319.             pi = 0;
  320.         }
  321.  
  322.     *procInfo = pi;
  323.     return aProc;
  324. }
  325.  
  326. /************************************************************************************ 
  327.  *     Return true if we can handle the selector, otherwise false.
  328.  */
  329.  
  330. pascal ComponentResult CDCanDo(Globals *storage, short selector) 
  331. {    
  332. #pragma unused(storage)
  333.     ProcInfoType ignoreResult;
  334.     
  335.     return (CDFindRoutineProcPtr(selector,&ignoreResult) != 0);
  336. }
  337.  
  338. /************************************************************************************ 
  339.  *    This gets called when the component instance is opened. We allocate our storage at this
  340.  *    point. If we have shared globals, we check if they exist, and put a pointer to them 
  341.  *    in our instance globals so that other calls can get to them.
  342.  */
  343.  
  344. pascal ComponentResult CDOpen(Globals *storage, ComponentInstance self)
  345. {
  346. #pragma unused(storage)
  347.     ComponentResult result;
  348.     Globals             *glob;
  349.     
  350.     /* 
  351.         First we allocate our local storage. This should store any
  352.         kind of data used by the component instance. It should be allocated
  353.         in the current heap.
  354.     */     
  355.          
  356.     if ( (glob = (Globals *)NewPtrClear(sizeof(Globals))) == nil )  {
  357.         return(MemError());
  358.     }
  359.     SetComponentInstanceStorage(self,(Handle)glob);
  360.     
  361.     /*     Check and initialize our shared globals */
  362.     
  363.     result = InitSharedTables(glob,self);
  364.  
  365. #if ASYNC_DECODE
  366.     /*
  367.         if we our doing an async decode, then make a routine descriptor for our
  368.         callback proc
  369.     */
  370.  
  371.     glob->decompressCallBackUPP = GetRoutineAddress(DecompressCallBack);
  372.  
  373.     // Start the world with every frame queued up on the free frame list 
  374.     // and nothing queued on the busy frame list.
  375.     {
  376.         short i;
  377.  
  378.         for(i=0; i<QUEUE_SIZE; i++){
  379.             DecompressRecord *drp = &glob->queue[i];
  380.             Enqueue((QElem *)&drp->nextFree, &glob->freeQueueHead);
  381.         }
  382.     }
  383.  
  384.         glob->target = self;
  385.  
  386. #endif
  387.  
  388.     return result;
  389. }
  390.  
  391. /************************************************************************************ 
  392.  *    This gets called when the component instance is opened. We allocate our shared storage at this
  393.  *    point. 
  394.  
  395.  *    If we have shared globals, we check if they exist, otherwise we allocate
  396.  *  them and set the ComponentRefCon so that other instances can use them.
  397.  *
  398.  *    The shared globals hold our CodecInfo struct, which we read from our resource file,
  399.  *  and some tables that we use for speed. If we cant get the tables we can work without
  400.  *  them. All items in the shared globals are made purgeable when the last of our 
  401.  *    instances is closed. If our component was loaded in the application heap ( because
  402.  *    there was no room in the system heap) then we keep our shared storage in the app heap.
  403.  *
  404.  *  We keep a pointer to the shared globals in our instance globals so that other calls can get to them.
  405.  */
  406.  
  407.  
  408. ComponentResult
  409. InitSharedTables(Globals *glob,ComponentInstance self)
  410. {
  411.     SharedGlobals    *sGlob;
  412.     long            i,j,*lp;
  413.     char            *cp;
  414.     short            resFile = kResFileNotOpened;
  415.     short            oldResFile;
  416.     THz                saveZone;
  417.     Boolean            inAppHeap;
  418.     OSErr            result = noErr;
  419.         
  420.      
  421.     oldResFile = CurResFile();
  422.     saveZone = GetZone();
  423.     inAppHeap = ( GetComponentInstanceA5(self) != 0 );
  424.     if ( !inAppHeap )
  425.         SetZone(SystemZone());
  426.     if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) == nil  ) {
  427.         if ( (sGlob = (SharedGlobals*)NewPtrClear(sizeof(SharedGlobals))) == nil ) { 
  428.             result = MemError();
  429.             goto obail;
  430.         } 
  431.         SetComponentRefcon((Component)self,(long)sGlob);
  432.     }
  433.  
  434.     glob->sharedGlob = sGlob;    // keep this around where it's easy to get at
  435.     
  436.  
  437.     if ( sGlob->info == nil || *(Handle)sGlob->info == nil  )  {
  438. #if TARGET_NON_MAC
  439.         Handle h;
  440. #endif
  441.         if ( sGlob->info ) 
  442.             DisposeHandle((Handle)sGlob->info);
  443. #if TARGET_NON_MAC
  444.         h = (CodecInfo **)NewHandleClear(sizeof(CodecInfo));
  445.         if (h && *h) {
  446.             CodecInfo ci = {
  447.                 "Example - YUV",                                /* name of the codec TYPE ( data format ) */
  448.                 1,                                                /* version */                            
  449.                 1,                                                /* revision */    
  450.                 OSTypeConst('appl'),                                            /* who made this codec */
  451.                 codecInfoDoes32 + codecInfoDoesSpool,                /* depth and etc. supported directly on decompress */    
  452.                 codecInfoDoes32 + codecInfoDoesSpool,                /* depth and etc supported directly on compress */
  453.                 codecInfoDepth16,                                /* which data formats do we understand */
  454.                 100,                                            /* compress accuracy (0-255) (relative to format) */
  455.                 100,                                            /* decompress accuracy (0-255) (relative to format) */
  456.                 200,                                            /* millisecs to compress 320x240 image on base Mac */
  457.                 200,                                            /* millisecs to decompress 320x240 image on base Mac */
  458.                 100,                                            /* compression level (0-255) (relative to format) */
  459.                 0,                                
  460.                 2,                                                /* minimum height */
  461.                 2,                                                /* minimum width */
  462.                 0,
  463.                 0,
  464.                 0
  465.             };
  466.             BlockMoveData(&ci,*h,sizeof(CodecInfo));
  467.         } else {
  468.             result = memFullErr;
  469.              h=0;
  470.        }
  471.        sGlob->info = h;
  472. #else
  473.         /* Get the CodecInfo struct which we keep in our resource fork */
  474.         
  475. #ifndef LINK_EXAMPLE_CODEC
  476.         resFile = OpenComponentResFile((Component)self);
  477.         if (resFile == kResFileNotOpened) {
  478.             result = memFullErr;
  479.             goto obail;
  480.         }
  481. #endif
  482. #ifndef POWERPC_NATIVE
  483.         sGlob->info = (CodecInfo **) Get1Resource(codecInfoResourceType,128);
  484. #else
  485.         sGlob->info = (CodecInfo **) Get1Resource(codecInfoResourceType,129);
  486. #endif
  487.         if ( sGlob->info == nil ) {
  488.             result = ResError();
  489.             goto obail;
  490.         }
  491.         LoadResource((Handle)sGlob->info);
  492.         if ( result = ResError() ) {
  493.             goto obail;
  494.         }
  495.         DetachResource((Handle)sGlob->info);
  496.     }
  497. #endif
  498.     HNoPurge((Handle)sGlob->info);
  499.     
  500.     if ( sGlob->rgbwTable == nil || *sGlob->rgbwTable == nil )  {
  501.         if ( sGlob->rgbwTable )
  502.             ReallocateHandle(sGlob->rgbwTable,3*256*sizeof(long));
  503.         else 
  504.             sGlob->rgbwTable = NewHandleSys(3*256*sizeof(long));
  505.             
  506.         /* we can actual still work without these tables, so we dont bail
  507.            if we cant get the memory for them */
  508.            
  509.         if ( sGlob->rgbwTable  && *sGlob->rgbwTable ) {
  510.             lp = (long *)*sGlob->rgbwTable;
  511.             for ( i=0, j = 0; i < 256; i++, j += R_W )
  512.                 *lp++ = j;
  513.             for ( i=0, j = 0; i < 256; i++, j += G_W )
  514.                 *lp++ = j;
  515.             for ( i=0, j = 0; i < 256; i++, j += B_W )
  516.                 *lp++ = j;
  517.         }
  518.     }
  519.     if ( sGlob->rgbwTable ) 
  520.         HNoPurge(sGlob->rgbwTable);            /* make sure it wont get purged while we are open */
  521.     
  522.     /* green inverse table */
  523.  
  524.     if ( sGlob->giwTable == nil || *sGlob->giwTable == nil  )  {
  525.         if ( sGlob->giwTable ) 
  526.             ReallocateHandle(sGlob->giwTable,256);
  527.         else 
  528.             sGlob->giwTable = NewHandleSys(256);
  529.  
  530.         /* we can actual still work without these tables, so we dont bail
  531.            if we cant get the memory for them */
  532.  
  533.         if ( sGlob->giwTable && *sGlob->giwTable  ) {
  534.             for ( i=0, cp = *sGlob->giwTable ; i < 256; i++ )
  535.                 *cp++ = PIN( (i<<16) / G_W);
  536.         }
  537.     }
  538.     if ( sGlob->giwTable ) 
  539.         HNoPurge(sGlob->giwTable);            /* make sure it wont get purged while we are open */
  540.  
  541.  
  542. obail:
  543. #ifndef LINK_EXAMPLE_CODEC
  544.     if (resFile != kResFileNotOpened)
  545.         CloseComponentResFile(resFile);
  546. #endif
  547.     UseResFile(oldResFile);
  548.     SetZone(saveZone);
  549.     if ( result != noErr && sGlob != nil ) {
  550.         if ( sGlob->rgbwTable )
  551.             DisposeHandle(sGlob->rgbwTable);
  552.         if ( sGlob->info )
  553.             DisposeHandle((Handle)sGlob->info);
  554.         DisposePtr((Ptr)sGlob);
  555.         SetComponentRefcon((Component)self,(long)nil);
  556.     }
  557.     return(result);
  558. }
  559.  
  560. /************************************************************************************ 
  561.  *    This gets called when the component instance is closed. We need to get rid of any 
  562.  *    instance storage here. 
  563.  */
  564.  
  565. pascal ComponentResult CDClose(Globals *storage,ComponentInstance self)
  566. {
  567.     SharedGlobals    *sGlob;
  568.     Globals            *glob = (Globals *)storage;
  569.         
  570.     /*    If we are closing our last instance 
  571.         then we make the shared global items purgeable to
  572.         speed things up next instance.
  573.      */
  574.     
  575.     if (glob) {
  576.         if ( CountComponentInstances((Component)self) == 1) {
  577.             if ( (sGlob=(SharedGlobals*)glob->sharedGlob) != nil  ) {
  578.                 if ( sGlob->rgbwTable )
  579.                     HPurge(sGlob->rgbwTable);
  580.                 if ( sGlob->giwTable )
  581.                     HPurge(sGlob->giwTable);
  582.                 if ( sGlob->info )
  583.                     HPurge((Handle)sGlob->info);
  584.             }
  585.         }
  586.  
  587. #if ASYNC_DECODE
  588.         if (glob->callBack) {
  589.             CDFlush((void *)glob);
  590.             DisposeCallBack(glob->callBack);
  591.         }
  592. #endif
  593.  
  594.         DisposePtr((Ptr)glob);
  595.     }
  596.     return(noErr);
  597. }
  598.  
  599.  
  600.  
  601. /************************************************************************************ 
  602.  *     Set the target for this component.
  603.  */
  604.  
  605. #if ASYNC_DECODE
  606. pascal ComponentResult CDTarget(Globals *storage,ComponentInstance target)
  607. {
  608.     Globals    *glob = (Globals *)storage;
  609.  
  610.     glob->target = target;
  611.  
  612.     return noErr;
  613. }
  614. #endif
  615.  
  616. /************************************************************************************ 
  617.  *    Return the version of this component ( defines interface ) and revision level
  618.  *    of the code.
  619.  */
  620.  
  621. pascal ComponentResult CDVersion(Globals *storage)
  622. {
  623.     return ((codecInterfaceVersion<<16) | EXAMPLE_CODEC_REV);        /* interface version in hi word, code rev in lo word  */
  624. }
  625.  
  626.  
  627. #if COMP_BUILD
  628.  
  629. /************************************************************************************ 
  630.  *    CDPreCompress gets called before an image is compressed, or whenever the source pixmap
  631.  *    pixel size changes when compressing a sequence. We return information about
  632.  *    how we can compress the image to the codec manager, so that it can fit the source data
  633.  *    to our requirements. The ImageDescriptor is already filled in, so we can use it for 
  634.  *    reference (or even add to it ). PixelSize is the pixel depth of the source pixmap, we
  635.  *    use this as a reference for deciding what we can do. The other parameters return information
  636.  *    to the CodecManager about what we can do. We can also do setup here if we want to.
  637.  */
  638.  
  639. pascal ComponentResult CDPreCompress(Globals *storage,register CodecCompressParams *p)
  640. {
  641.     CodecCapabilities *capabilities = p->capabilities;
  642.  
  643.     /*
  644.      *    First we return which depth input pixels we can deal with - based on what the
  645.      *    app has available - we can only work with 32 bit input pixels.
  646.      */
  647.        
  648.     switch ( (*p->imageDescription)->depth )  {
  649.         case 16:
  650.             capabilities->wantedPixelSize = 32;
  651.             break;
  652.         default:
  653.             return(codecConditionErr);
  654.             break;
  655.     }
  656.  
  657.     /* if the buffer gets banded,  return the smallest one we can deal with */
  658.     
  659.     capabilities->bandMin = 2;
  660.  
  661.     /* if the buffer gets banded, return the increment it be should grown */
  662.  
  663.     capabilities->bandInc = 2;
  664.     
  665.     
  666.     /*
  667.      *    If a codec needs the dimensions of the source pixmap to be of certain multiples
  668.      *    it can ask for the image to be extended out (via pixel replication) vertically
  669.      *    and/or horizontally.
  670.      *
  671.      *    In our case, we're dealing with 2 by 2 blocks and therefore we want the image
  672.      *    height and width to both be multiples of 2.  If either dimension is odd, we
  673.      *    ask it have it extended by one pixel.
  674.      */
  675.  
  676.     capabilities->extendWidth = (*p->imageDescription)->width & 1;
  677.     capabilities->extendHeight = (*p->imageDescription)->height & 1;
  678.     
  679.     return(noErr);
  680. }
  681.  
  682.  
  683. /************************************************************************************ 
  684.  *    CDBandCompress gets called when the codec manager wants us to compress an image, or a horizontal 
  685.  *    band of an image. The pixel data at sBaseAddr is guaranteed to conform to the criteria we 
  686.  *    demanded in BeginCompress.
  687.  */
  688.  
  689. pascal ComponentResult CDBandCompress(Globals *storage,register CodecCompressParams *p)
  690. {
  691.     short                width,height;
  692.     Ptr                    cDataPtr,dataStart;
  693.     short                depth;
  694.     Rect                sRect;
  695.     long                offsetH,offsetV;
  696.     Globals                *glob  = (Globals *)storage;
  697.     char                 *baseAddr;
  698.     long                numLines,numStrips;
  699.     short                rowBytes;
  700.     long                stripBytes;
  701.     char                mmuMode = 1;
  702.     short                y;
  703.     ImageDescription    **desc = p->imageDescription;
  704.     OSErr                result = noErr;
  705.     
  706.     /*    If there is a progress proc, give it an open call at the start of this band. */
  707.  
  708.     if (p->progressProcRecord.progressProc)
  709.         CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressOpen,0,
  710.             p->progressProcRecord.progressRefCon);
  711.  
  712.     width = (*desc)->width;
  713.     height = (*desc)->height;
  714.     depth = (*desc)->depth;
  715.     dataStart = cDataPtr = p->data;
  716.  
  717.     /* figure out offset to first pixel in baseAddr from the pixelsize and bounds */
  718.  
  719.     rowBytes = p->srcPixMap.rowBytes & 0x3fff;
  720.     sRect =  p->srcPixMap.bounds;
  721.     numLines = p->stopLine - p->startLine;        /* number of scanlines in this band */
  722.     numStrips = (numLines+1)>>1;                /* number of strips in this band */
  723.     stripBytes = ((width+1)>>1) * 5;
  724.     
  725.     /* adjust the source baseAddress to be at the beginning of the desired rect */
  726.  
  727.     switch ( p->srcPixMap.pixelSize ) {
  728.     case 32:
  729.         offsetH = sRect.left<<2;
  730.         break;
  731.     case 16:
  732.         offsetH = sRect.left<<1;
  733.         break;
  734.     case 8:
  735.         offsetH = sRect.left;
  736.         break;
  737.     default:
  738.         result = codecErr;
  739.         goto bail;
  740.     }
  741.     offsetV = sRect.top * rowBytes;
  742.     baseAddr = p->srcPixMap.baseAddr + offsetH + offsetV;
  743.  
  744.  
  745.     /* if there is not a flush proc, adjust the pointer to the next band */
  746.     
  747.     if (  p->flushProcRecord.flushProc == nil )
  748.         cDataPtr += (p->startLine>>1) * stripBytes;
  749.     else {
  750.         if ( p->bufferSize < stripBytes ) {
  751.             result = codecSpoolErr;
  752.             goto bail;
  753.         }
  754.     }
  755.  
  756.  
  757.     /* do the slower flush/progress case if we have too */
  758.     
  759.     if (  p->flushProcRecord.flushProc  || p->progressProcRecord.progressProc ) {
  760.         SharedGlobals *sg = glob->sharedGlob;
  761.  
  762.  
  763.         for ( y=0; y < numStrips; y++) {
  764.             SwapMMUMode(&mmuMode);
  765.             CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
  766.             SwapMMUMode(&mmuMode);
  767.             baseAddr += rowBytes<<1;
  768.             if ( p->flushProcRecord.flushProc ) { 
  769.                 if ( (result=CallICMFlushProc(p->flushProcRecord.flushProc,cDataPtr,stripBytes,
  770.                         p->flushProcRecord.flushRefCon)) != noErr) {
  771.                     result = codecSpoolErr;
  772.                     goto bail;
  773.                 }
  774.             } else {
  775.                 cDataPtr += stripBytes;
  776.             }
  777.             if (p->progressProcRecord.progressProc) {
  778.                 if ( (result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent,
  779.                     FixDiv(y,numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
  780.                         result = codecAbortErr;
  781.                         goto bail;
  782.                     }
  783.             }
  784.         }
  785.     } else {
  786.         SharedGlobals *sg = glob->sharedGlob;
  787.         short    tRowBytes = rowBytes<<1;
  788.  
  789.         SwapMMUMode(&mmuMode);
  790.         for ( y=numStrips; y--; ) {
  791.             CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
  792.             cDataPtr += stripBytes;
  793.             baseAddr += tRowBytes;
  794.         }
  795.         SwapMMUMode(&mmuMode);
  796.     }
  797.  
  798.     /*
  799.     
  800.         return size and similarity on the last band 
  801.         
  802.     */
  803.     
  804.     if ( p->conditionFlags & codecConditionLastBand ) {
  805.         (*p->imageDescription)->dataSize = stripBytes * ((height+1)>>1);    /* return the actual size of the compressed data */
  806.         p->similarity = 0;                            /* we don't do frame differencing */
  807.     }
  808.     
  809. bail:
  810.     /*    If there is a progress proc, give it a close call at the end of this band. */
  811.  
  812.     if (p->progressProcRecord.progressProc)
  813.         CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0,
  814.             p->progressProcRecord.progressRefCon);
  815.         
  816.     return(result);
  817. }
  818.  
  819. #endif
  820.  
  821. pascal ComponentResult CDBusy(Globals *storage, ImageSequence seq)
  822. {
  823. #pragma    unused(seq)
  824. #if ASYNC_DECODE && QT_MP
  825.     // and return true if there is still something goin' on
  826.     return TestBusy( (Globals *)storage );
  827. #else
  828.     return 0;
  829. #endif
  830. }
  831.  
  832. #if ASYNC_DECODE
  833.  
  834. /*
  835.     CDFlush is called when the image compression manager wants the 
  836.     codec to empty its schedule queue. An example would be when a movie is
  837.     playing and the user moves the thumb. The sudden jump in time renders
  838.     any previously scheduled frames useless. So we need to flush the queue so
  839.     we can start over.
  840. */
  841. pascal ComponentResult CDFlush(Globals *storage)
  842. {
  843.     Globals *glob = (Globals *)storage;
  844.  
  845.     /*
  846.         if there's not a callback proc allocated, we sure don't have any frames
  847.         queued up.
  848.     */
  849.     if (glob->callBack) {
  850.         DecompressRecord *drp;
  851.         long saveA5 = SetA5(glob->a5World);
  852.  
  853.         glob->queueIsRunning = false;    // flag queue as not running. 
  854.                                         // otherwise, we'll never start it up again
  855.  
  856.         // kill the callback
  857.         CancelCallBack(glob->callBack);
  858.  
  859. #if QT_MP
  860.         // wait for things to stop
  861.         while( TestBusy( glob ) )
  862.             ;
  863. #endif
  864.  
  865.         // tear down the queue
  866.         while (drp = (DecompressRecord *)glob->busyQueueHead.qHead) {
  867.             drp = (DecompressRecord *)(((long)drp) - fieldOffset(DecompressRecord, nextBusy));
  868.             Dequeue((QElem *)&drp->nextBusy, &glob->busyQueueHead);
  869.  
  870.             if (drp->srcData) {
  871.                 // call back to say we're done
  872.                 ICMDecompressComplete(glob->sequenceID, -1, codecCompletionSource | codecCompletionDest, &drp->completionProc);
  873.                 Enqueue((QElem *)&drp->nextFree, &glob->freeQueueHead);
  874.                 drp->srcData = nil;
  875.             }
  876.         }
  877.  
  878.         SetA5(saveA5);
  879.     }
  880.  
  881.     return (noErr);
  882. }
  883.  
  884. #if QT_MP
  885. pascal ComponentResult CDGetMPWorkFunction(Globals *storage, ComponentMPWorkFunctionUPP *workFunction, void **refCon)
  886. {
  887.     Globals *glob = (Globals *)storage;
  888.  
  889.     *workFunction = (ComponentMPWorkFunctionUPP)GetRoutineAddress(DecompressWorkFunction);
  890.     *refCon = storage;
  891.  
  892.     return noErr;
  893. }
  894. #endif // QT_MP
  895.  
  896. #endif // ASYNC_DECODE
  897.  
  898.  
  899. #if DECO_BUILD
  900.  
  901.  
  902. /************************************************************************************ 
  903.  *    CDPreDecompress gets called before an image is decompressed. We return information about
  904.  *    how we can decompress the image to the codec manager, so that it can fit the destination data
  905.  *    to our requirements. 
  906.  */
  907.  
  908. pascal ComponentResult CDPreDecompress(Globals *storage,register CodecDecompressParams *p)
  909. {
  910.     Globals    *glob  = (Globals *)storage;
  911.     register CodecCapabilities    *capabilities = p->capabilities;
  912.  
  913.     /*    Decide which depth compressed data we can deal with. */
  914.     
  915.     switch ( (*p->imageDescription)->depth )  {
  916.         case 16:
  917.             break;
  918.         default:
  919.             return(codecConditionErr);
  920.             break;
  921.     }
  922.     
  923.     /*    We can deal only 32 bit pixels. */
  924.  
  925.     capabilities->wantedPixelSize = 32;    
  926.     
  927.     /*    The smallest possible band we can do is 2 scan lines. */
  928.     
  929.     capabilities->bandMin = 2;
  930.  
  931.     /*    We can deal with 2 scan line high bands. */
  932.  
  933.     capabilities->bandInc = 2;
  934.     
  935.     /*    If we needed our pixels to be aligned on some integer multiple we would set these to
  936.      *    the number of pixels we need the dest extended by. If we dont care, or we take care of
  937.      *  it ourselves we set them to zero.
  938.      */
  939.  
  940.     capabilities->extendWidth = p->srcRect.right & 1;
  941.     capabilities->extendHeight = p->srcRect.bottom & 1;
  942. #if ASYNC_DECODE
  943.     if (glob->decompressFunction == nil) {
  944. #if QT_MP
  945.         CallComponentGetMPWorkFunction(glob->target, &glob->decompressFunction, &glob->decompressFunctionRefCon);
  946. #else
  947.         glob->decompressFunction = (ComponentMPWorkFunctionUPP)GetRoutineAddress(DecompressWorkFunction);
  948.         glob->decompressFunctionRefCon = glob;
  949. #endif
  950.     }
  951.  
  952.     capabilities->flags = codecCanAsyncWhen | codecCanAsync | codecCanShieldCursor;
  953.     glob->sequenceID = p->sequenceID;
  954. #else
  955.     capabilities->flags = 0;
  956. #endif
  957.     return(noErr);
  958. }
  959.  
  960. #if ASYNC_DECODE
  961.  
  962. pascal ComponentResult DecompressWorkFunction(Globals *glob, DecompressRecord *drp)
  963. {
  964.     if (drp->header.workFlags & mpWorkFlagGetProcessorCount)
  965.         drp->header.processorCount = 1;
  966.  
  967.     if (drp->header.workFlags & mpWorkFlagDoWork) {
  968.         short y;
  969.         char mmuMode = true32b;            // we want to be in 32-bit mode
  970.         Ptr cDataPtr = drp->srcData;        // compressed data pointer;
  971.         Ptr baseAddr = drp->baseAddr;        // base address of dest PixMap;
  972.  
  973.         SwapMMUMode(&mmuMode);            // put us in 32-bit mode
  974.         for ( y=drp->numStrips; y--; ) {
  975.             DecompressStrip(cDataPtr,baseAddr,drp->rowBytes,drp->width,glob->sharedGlob);
  976.             baseAddr += drp->baseAddrIncrement;
  977.             cDataPtr += drp->srcDataIncrement;
  978.         }
  979.         SwapMMUMode(&mmuMode);            // back to our old memory mode
  980.     }
  981.  
  982.     if (drp->header.workFlags & mpWorkFlagDoCompletion) {
  983.         glob->decompressCount--;
  984.  
  985.         ICMDecompressComplete(glob->sequenceID, noErr, codecCompletionSource | codecCompletionDest, &drp->completionProc);
  986.  
  987.         drp->srcData = nil;
  988.  
  989.         if (drp->inQueue) {
  990.             Dequeue((void *)&drp->nextBusy, &glob->busyQueueHead);
  991.             Enqueue((void *)&drp->nextFree, &glob->freeQueueHead);
  992.  
  993.             // queue up the next one
  994.             if (glob->queueIsRunning && (drp = (void *)glob->busyQueueHead.qHead)) {
  995.                 drp = (void *)((Ptr)drp - (Ptr)fieldOffset(DecompressRecord, nextBusy));
  996.                 CallMeWhen(
  997.                         glob->callBack,
  998.                         glob->decompressCallBackUPP,
  999.                         (long)drp,
  1000.                         (drp->rate >= 0) ? triggerTimeFwd : triggerTimeBwd,
  1001.                         (long)drp->frameTime,
  1002.                         (long)drp->scale);
  1003.             }
  1004.             else {
  1005.                 glob->queueIsRunning = false;
  1006.             }
  1007.         }
  1008.     }
  1009.  
  1010.     return noErr;
  1011. }
  1012.  
  1013. /*
  1014.     This is the call back proc that is used for scheduled asynchronously displayed
  1015.     frames. It is called at the scheduled frame time, and should display that
  1016.     frame. If there is a frame queued up after this one, it should be scheduled.
  1017. */
  1018. pascal void DecompressCallBack(QTCallBack cb,long refcon)
  1019. {
  1020.     DecompressRecord *drp = (DecompressRecord *)refcon;
  1021.     Globals *glob = (Globals *)drp->glob;
  1022.  
  1023.     if (drp->srcData) {
  1024.         if (drp->shieldCursor) {
  1025.             ICMShieldSequenceCursor(glob->sequenceID);
  1026.             drp->shieldCursor = false;
  1027.         }
  1028.  
  1029.         drp->header.headerSize = sizeof(ComponentMPWorkFunctionHeaderRecord);
  1030.         drp->header.recordSize = sizeof(DecompressRecord);
  1031.         drp->header.workFlags = mpWorkFlagDoWork | mpWorkFlagDoCompletion;
  1032.         if (!drp->inQueue)
  1033.             drp->header.workFlags |= mpWorkFlagCopyWorkBlock;
  1034.  
  1035.         glob->decompressCount++;
  1036.         CallComponentMPWorkFunctionProc(glob->decompressFunction, glob->decompressFunctionRefCon, (void *)drp);
  1037.     }
  1038. }
  1039.  
  1040. #endif
  1041.  
  1042.  
  1043. /************************************************************************************ 
  1044.  *    CDBandDecompress gets called when the codec manager wants us to decompress an image or a horizontal 
  1045.  *    band of an image. The pixel data at baseAddr is guaranteed to conform to the criteria we 
  1046.  *    demanded in BeginDecompress. If maskIn is true, then the mask data at mBaseAddr is valid, and
  1047.  *    we need to clear bits in it that correspond to any pixels in the destination we do not want to 
  1048.  *    change. ( We always write all pixels, so we dont care. This mode is important only for those
  1049.  *    codecs that have frame differencing and don't always write all the pixels. )
  1050.  */
  1051.  
  1052. pascal ComponentResult CDBandDecompress(Globals *storage,register CodecDecompressParams *p)
  1053. {
  1054.     long                offsetH,offsetV;
  1055.     Globals                *glob  = (Globals *)storage;
  1056.     long                numLines,numStrips;
  1057.     short                rowBytes;
  1058.     long                stripBytes;
  1059.     short                width;
  1060.     short                y;
  1061.     char                *baseAddr;
  1062.     char                *cDataPtr;
  1063.     char                mmuMode = 1;
  1064.     OSErr                result = noErr;
  1065.     
  1066.     /*    If there is a progress proc, give it an open call at the start of this band. */
  1067.  
  1068.     if (p->progressProcRecord.progressProc)
  1069.         CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressOpen,0,
  1070.             p->progressProcRecord.progressRefCon);
  1071.  
  1072.  
  1073.  
  1074.     /* initialize some local variables */
  1075.     
  1076.     width = (*p->imageDescription)->width;
  1077.     rowBytes = p->dstPixMap.rowBytes;                    
  1078.     numLines = p->stopLine - p->startLine;            /* number of scanlines in this band */
  1079.     numStrips = (numLines+1)>>1;                    /* number of strips in this band */
  1080.     stripBytes = ((width+1)>>1) * 5;                /* number of bytes in one strip of blocks */
  1081.     cDataPtr = p->data;
  1082.     
  1083.     /* adjust the destination baseaddress to be at the beginning of the desired rect */
  1084.     
  1085.     offsetH = (p->dstRect.left - p->dstPixMap.bounds.left);
  1086.     offsetH <<=2;                    /* 1 pixel = 4 bytes */
  1087.     offsetV = (p->dstRect.top - p->dstPixMap.bounds.top) * rowBytes;
  1088.     baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV;
  1089.  
  1090.  
  1091.     /* 
  1092.      *    If we are skipping some data, we just skip it here. We can tell because
  1093.      *    firstBandInFrame says this is the first band for a new frame, and
  1094.      *    if startLine is not zero, then that many lines were clipped out.
  1095.      */
  1096.  
  1097.     if ( (p->conditionFlags & codecConditionFirstBand) && p->startLine != 0 ) {
  1098.         if ( p->dataProcRecord.dataProc ) {
  1099.             for ( y=0; y  < p->startLine>>1; y++ )  {
  1100.                 if ( (result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes,
  1101.                         p->dataProcRecord.dataRefCon)) != noErr ) {
  1102.                     result = codecSpoolErr;
  1103.                     goto bail;
  1104.                 }
  1105.                 cDataPtr += stripBytes;
  1106.             }
  1107.         } else
  1108.             cDataPtr += (p->startLine>>1) * stripBytes;
  1109.     }
  1110.     
  1111.     /*
  1112.      *    If theres a dataproc spooling the data to us, then we have to do the data
  1113.      *    in whatever size chunks they want to give us, or if there is a progressProc
  1114.      *  make sure to call it as we go along.
  1115.      */
  1116.     
  1117.     if ( p->dataProcRecord.dataProc || p->progressProcRecord.progressProc ) {
  1118.         SharedGlobals *sg = glob->sharedGlob;
  1119.     
  1120. #if ASYNC_DECODE
  1121.         if (p->conditionFlags & codecConditionDoCursor)
  1122.             ICMShieldSequenceCursor(p->sequenceID);
  1123. #endif
  1124.  
  1125.         for (y=0; y < numStrips; y++) {
  1126.             if (p->dataProcRecord.dataProc) {
  1127.                 if ( (result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes,
  1128.                         p->dataProcRecord.dataRefCon)) != noErr ) {
  1129.                     result = codecSpoolErr;
  1130.                     goto bail;
  1131.                 }
  1132.             }
  1133.             SwapMMUMode(&mmuMode);
  1134.             DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
  1135.             SwapMMUMode(&mmuMode);
  1136.             baseAddr += rowBytes<<1;
  1137.             cDataPtr += stripBytes;
  1138.             if (p->progressProcRecord.progressProc) {
  1139.                 if ( (result=CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressUpdatePercent,
  1140.                     FixDiv(y, numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
  1141.                     result = codecAbortErr;
  1142.                      goto bail;
  1143.                 }
  1144.             }
  1145.         }
  1146.         ICMDecompressComplete(p->sequenceID, noErr, codecCompletionSource | codecCompletionDest, &p->completionProcRecord);
  1147.  
  1148.     /* 
  1149.      *
  1150.      * otherwise - do the fast case. 
  1151.      *
  1152.      */
  1153.          
  1154.     } else {
  1155.         DecompressRecord stackDecompressRecord;
  1156.         DecompressRecord *drp = &stackDecompressRecord;
  1157.  
  1158. #if ASYNC_DECODE
  1159.         if (p->frameTime) {
  1160.             if (!glob->freeQueueHead.qHead) {
  1161.                 result = codecCantQueueErr;
  1162. errorReturn:
  1163.                 ICMDecompressComplete(p->sequenceID, result, codecCompletionSource | codecCompletionDest, &p->completionProcRecord);
  1164.                 goto bail;
  1165.             }
  1166.  
  1167.             if (!glob->callBack) {
  1168.                 // there is no current callback. allocate one.
  1169.                 glob->callBack = NewCallBack(p->frameTime->base,callBackAtTime + callBackAtInterrupt + callBackAtDeferredTask);
  1170.                 if (!glob->callBack) {
  1171.                     result = codecCantQueueErr;
  1172.                     goto errorReturn;
  1173.                 }
  1174.                 glob->a5World = SetA5(0);
  1175.                 SetA5(glob->a5World);            // is there a way to get a5 without changing it?
  1176.             }
  1177.             drp = (void *)((Ptr)glob->freeQueueHead.qHead - (Ptr)fieldOffset(DecompressRecord, nextFree));
  1178.             Dequeue((void *)&drp->nextFree, &glob->freeQueueHead);
  1179.         }
  1180. #endif // ASYNC_DECODE
  1181.  
  1182.         drp->srcData = cDataPtr;
  1183.         drp->baseAddr = baseAddr;
  1184.         drp->rowBytes = rowBytes;
  1185.         drp->width = width;
  1186.         drp->numStrips = numStrips;
  1187.         drp->srcDataIncrement = stripBytes;
  1188.         drp->baseAddrIncrement = rowBytes<<1;
  1189.         drp->completionProc = p->completionProcRecord;
  1190.         drp->frameTime = p->frameTime->value.lo;
  1191.         drp->scale = p->frameTime->scale;
  1192.         drp->rate = p->frameTime->rate;
  1193.         drp->shieldCursor = (p->conditionFlags & codecConditionDoCursor) != 0;
  1194.         drp->glob = (void *)glob;
  1195.  
  1196.  
  1197. #if ASYNC_DECODE
  1198.         glob->sequenceID = p->sequenceID;
  1199.  
  1200.         if (p->frameTime) {
  1201.             drp->inQueue = true;
  1202.             Enqueue((void *)(&drp->nextBusy), &glob->busyQueueHead);    // put the frame in the queue
  1203.             if (!glob->queueIsRunning) {
  1204.                 // the queue isn't running... start it up
  1205.                 glob->queueIsRunning = true;    // since CallMeWhen could be considered "CallMeRightNow"
  1206.                 if (result = CallMeWhen(
  1207.                         glob->callBack,
  1208.                         glob->decompressCallBackUPP,
  1209.                         (long)drp,
  1210.                         (drp->rate >= 0) ? triggerTimeFwd : triggerTimeBwd,
  1211.                         (long)drp->frameTime,
  1212.                         (long)drp->scale)) {
  1213.                     // there was an error
  1214.                     glob->queueIsRunning = false;    // if error, queue isn't running
  1215.                     drp->srcData = nil;
  1216.                     Dequeue((void *)&drp->nextBusy, &glob->busyQueueHead);
  1217.                     Enqueue((void *)&drp->nextFree, &glob->freeQueueHead);
  1218.                     goto errorReturn;
  1219.                 }
  1220.             }
  1221.         } 
  1222.         else 
  1223. #endif // ASYNC_DECODE
  1224.         {
  1225.             drp->inQueue = false;
  1226.  
  1227.             DecompressCallBack(nil, (long)drp);
  1228.             cDataPtr += *(long *)p->data & 0x00FFFFFF;
  1229.         }
  1230.     }
  1231.     
  1232.     /* 
  1233.      *
  1234.      *  IMPORTANT: update pointer to data in params, so when we get the  next
  1235.      *  band we'll be at the right place in our data.
  1236.      *  
  1237.      */
  1238.     
  1239.     p->data = cDataPtr;
  1240.     
  1241.     if ( p->conditionFlags & codecConditionLastBand ) {
  1242.         /* Tie up any loose ends on the last band of the frame, if we had any */
  1243.     }
  1244.  
  1245. bail:
  1246.     /*    If there is a progress proc, give it a close call at the end of this band. */
  1247.  
  1248.     if (p->progressProcRecord.progressProc)
  1249.         CallICMProgressProc(p->progressProcRecord.progressProc,codecProgressClose,0,
  1250.             p->progressProcRecord.progressRefCon);
  1251.  
  1252.     return result;
  1253. }
  1254.  
  1255. #endif // DECO_BUILD
  1256.  
  1257. /************************************************************************************ 
  1258.  *    CDGetCodecInfo allows us to return information about ourselves to the codec manager.
  1259.  *    
  1260.  *    There will be a tool for determining appropriate values for the accuracy, speed
  1261.  *    and level information. For now we estimate with scientific wild guessing.
  1262.  *
  1263.  *  The info is stored as a resource in the same file with our component.
  1264.  */
  1265.  
  1266. pascal ComponentResult CDGetCodecInfo(Globals *storage,CodecInfo *info)
  1267. {
  1268.     Globals *glob = (Globals *)storage;
  1269.  
  1270.     if ( info == nil ) 
  1271.         return(paramErr);
  1272.     BlockMoveData((Ptr)*(glob->sharedGlob)->info,(Ptr)info,sizeof(CodecInfo));
  1273.     return(noErr);
  1274. }
  1275.  
  1276.  
  1277. #if DECO_BUILD
  1278. /************************************************************************************ 
  1279.  *    When CDGetCompressedImageSize is called, we return the size in bytes of the given compressed
  1280.  *    data ( for one image frame).
  1281.  */
  1282.  
  1283. pascal ComponentResult CDGetCompressedImageSize(Globals *storage,ImageDescriptionHandle desc,Ptr data,
  1284.     long dataSize, ICMDataProcRecordPtr dataProc,long *size)
  1285. {
  1286. #pragma    unused(storage,data,dataSize,dataProc)
  1287.  
  1288.     short    width =(*desc)->width;
  1289.     short    height = (*desc)->height;
  1290.     
  1291.     if ( size == nil )
  1292.         return(paramErr);
  1293.         
  1294.     /*
  1295.      *    Our data has a size which is deterministic based on the image size. If it were not we
  1296.      *    could encode the size in the compressed data, or figure it out by walking the
  1297.      *    compressed data.
  1298.      */
  1299.      
  1300.     *size = ((width+1)/2) * 5 * ((height+1)/2);
  1301.     return(noErr);
  1302. }
  1303. #endif // DECO_BUILD
  1304.  
  1305. #if COMP_BUILD
  1306. /************************************************************************************ 
  1307.  *    When CDGetMaxCompressionSize is called, we return the maximum size the compressed data for
  1308.  *    the given image would be in bytes.
  1309.  */
  1310.  
  1311. pascal ComponentResult CDGetMaxCompressionSize(Globals *storage,PixMapHandle src,
  1312.     const Rect *srcRect,short depth, CodecQ quality,long *size)
  1313. {
  1314. #pragma    unused(storage,src,depth,quality)
  1315.     
  1316.     short width = srcRect->right - srcRect->left;
  1317.     short height = srcRect->bottom - srcRect->top;
  1318.  
  1319.     /*    we always end up with a fixed size. If we did not, we would return the worst case size */
  1320.     
  1321.     *size = ((width+1)/2) * 5 * ((height+1)/2);    
  1322.  
  1323.     return(noErr);
  1324. }
  1325.  
  1326.  
  1327. /************************************************************************************ 
  1328.  *    When CDGetCompressionTime is called, we return the approximate time for compressing
  1329.  *    the given image would be in milliseconds. We also return the closest actual quality
  1330.  *    we can handle for the requested value.
  1331.  */
  1332.  
  1333. pascal ComponentResult CDGetCompressionTime(Globals *storage,PixMapHandle src,
  1334.         const Rect *srcRect,short depth,CodecQ *spatialQuality,CodecQ *temporalQuality,
  1335.         unsigned long *time)
  1336. {
  1337. #pragma    unused(storage,src,srcRect,depth)
  1338.  
  1339.     if (time)
  1340.         *time = 0;                                    /* we don't know how many msecs */
  1341.  
  1342.     if (spatialQuality)
  1343.         *spatialQuality = codecNormalQuality;        /* we have only one quality level for now */
  1344.     
  1345.     if (temporalQuality)
  1346.         *temporalQuality = 0;                        /* we cannot do temporal compression */
  1347.  
  1348.     return(noErr);
  1349. }
  1350.  
  1351. #endif // COMP_BUILD
  1352.  
  1353. #if DECO_BUILD
  1354.  
  1355. /************************************************************************************ 
  1356.  *    When CDTrimImage is called, we take the given compressed data and return only the portion
  1357.  *    which is represented by the trimRect. We can return a little more if we have too, but we
  1358.  *    need only return enough so that the image in trimRect is properly displayed. We then
  1359.  *    adjust the rectangle to corresond to the same rectangle in the new trimmed data.
  1360.  */
  1361.  
  1362. pascal ComponentResult CDTrimImage(Globals *storage,ImageDescriptionHandle desc,Ptr inData,
  1363.         long inDataSize,ICMDataProcRecordPtr dataProc,Ptr outData,long outDataSize,
  1364.         ICMFlushProcRecordPtr flushProc,Rect *trimRect,ICMProgressProcRecordPtr progressProc)
  1365. {
  1366. #pragma    unused(storage)
  1367.  
  1368.     Rect    rect = *trimRect;
  1369.     char    *dataP,*odP,*startP;
  1370.     short    trimOffTop;
  1371.     short    trimOffBottom;
  1372.     short    trimOffLeft;
  1373.     short    trimOffRight;
  1374.     short    bytesOffLeft;
  1375.     short    newHeight,newWidth;
  1376.     long    size;
  1377.     short    stripBytes;
  1378.     short    newStripBytes;
  1379.     short    i,y;
  1380.     OSErr    result = noErr;
  1381.     
  1382.         
  1383.     if ( dataProc->dataProc == nil )
  1384.         dataProc = nil;
  1385.     if ( flushProc->flushProc == nil )
  1386.         flushProc = nil;
  1387.     if ( progressProc->progressProc == nil )
  1388.         progressProc = nil;
  1389.     if ( progressProc ) 
  1390.         CallICMProgressProc(progressProc->progressProc,codecProgressOpen,0,progressProc->progressRefCon);
  1391.  
  1392.     dataP = inData;
  1393.     newHeight = (*desc)->height;
  1394.     newWidth = (*desc)->width;
  1395.     stripBytes = ((newWidth+1)>>1) * 5;            /* the number of bytes in a strip (2-scanlines/strip) */
  1396.     
  1397.     /* figure out how many 2x2 blocks we want to strip from each side of the image */
  1398.  
  1399.     trimOffTop = rect.top>>1;
  1400.     trimOffBottom  = (newHeight - rect.bottom) >> 1;
  1401.     trimOffLeft = rect.left>>1;
  1402.     trimOffRight  = (newWidth - rect.right) >> 1;
  1403.  
  1404.     /* point to the start of the first strip we are using */
  1405.  
  1406.     startP  = dataP + stripBytes * trimOffTop;
  1407.  
  1408.  
  1409.     /* make the trim values pixel based */
  1410.     
  1411.     trimOffLeft <<= 1;
  1412.     trimOffTop <<= 1;
  1413.     trimOffBottom <<= 1;
  1414.     trimOffRight <<= 1;
  1415.     
  1416.     /* calculate new height and width */
  1417.     
  1418.     newHeight -= trimOffTop + trimOffBottom;
  1419.     newWidth -=  trimOffLeft + trimOffRight;
  1420.     
  1421.     /* calc size in bytes of strips of the new width */
  1422.     
  1423.     newStripBytes = ((newWidth+1)>>1) * 5;        
  1424.  
  1425.     /* figure number of bytes to toss at the beginning of each strip  */
  1426.     
  1427.     bytesOffLeft = (trimOffLeft>>1) * 5;
  1428.  
  1429.     /* figure size of new trimmed image */
  1430.     
  1431.     size = newStripBytes * (newHeight>>1);
  1432.     
  1433.     /* make sure it's gonna fit */
  1434.     
  1435.     if ( size > outDataSize )  {
  1436.         result = codecErr;
  1437.         goto bail;
  1438.     }
  1439.         
  1440.     /* now go through the strips and copy the needed portion of each to the new data */
  1441.  
  1442.     if (  dataProc ) {
  1443.         short rightBytes = stripBytes - newStripBytes - bytesOffLeft;
  1444.         for ( y=0; y < trimOffTop; y++ ) {
  1445.             if ( (result=CallICMDataProc(dataProc->dataProc,&inData,stripBytes,dataProc->dataRefCon)) != noErr )
  1446.                 goto bail;
  1447.             inData += stripBytes;
  1448.             if (progressProc ) {
  1449.                 if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
  1450.                     FixDiv(y, (*desc)->height),progressProc->progressRefCon)) != noErr)  {
  1451.                     result = codecAbortErr;
  1452.                     goto bail;
  1453.                 }
  1454.             }
  1455.         }
  1456.         for ( y=0; y < newHeight; y+= 2) {
  1457.             if ( bytesOffLeft ) {
  1458.                 if ( (result=CallICMDataProc(dataProc->dataProc,&inData,bytesOffLeft,dataProc->dataRefCon)) != noErr )
  1459.                     goto bail;
  1460.                 inData += bytesOffLeft;
  1461.             }
  1462.             if ( (result=CallICMDataProc(dataProc->dataProc,&inData,newStripBytes,dataProc->dataRefCon)) != noErr )
  1463.                 goto bail;
  1464.             if (  flushProc ) {
  1465.                 if ( (result=CallICMFlushProc(flushProc->flushProc,inData,newStripBytes,flushProc->flushRefCon)) != noErr ) {
  1466.                     result = codecSpoolErr;
  1467.                     goto bail;
  1468.                 }
  1469.             }
  1470.             else {
  1471.                 BlockMoveData(inData,outData,newStripBytes);
  1472.                 outData += newStripBytes;
  1473.             }
  1474.             inData += newStripBytes;
  1475.             if ( rightBytes ) {
  1476.                 if ( (result=CallICMDataProc(dataProc->dataProc,&inData,rightBytes,dataProc->dataRefCon)) != noErr ) {
  1477.                     result = codecSpoolErr;
  1478.                     goto bail;
  1479.                 }
  1480.                 inData += rightBytes;
  1481.             }
  1482.             if (progressProc) {
  1483.                 if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
  1484.                     FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
  1485.                     result = codecAbortErr;
  1486.                     goto bail;
  1487.                 }
  1488.             }
  1489.         }
  1490.     }
  1491.     else {
  1492.         inData += stripBytes * trimOffTop;
  1493.         for ( y=0; y < newHeight; y += 2, inData += stripBytes) {
  1494.             if (  flushProc ) {
  1495.                 if ( (result=CallICMFlushProc(flushProc->flushProc,inData + bytesOffLeft,newStripBytes,flushProc->flushRefCon)) != noErr ) {
  1496.                     result = codecSpoolErr;
  1497.                     goto bail;
  1498.                 }
  1499.             }
  1500.             else {
  1501.                 BlockMoveData(inData + bytesOffLeft,outData,newStripBytes);
  1502.                 outData += newStripBytes;
  1503.             }
  1504.             if (progressProc ) {
  1505.                 if ( (result=CallICMProgressProc(progressProc->progressProc,codecProgressUpdatePercent,
  1506.                     FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
  1507.                     result = codecAbortErr;
  1508.                     goto bail;
  1509.                 }
  1510.             }
  1511.         }
  1512.     }
  1513.  
  1514.     /* adjust the rectangle to reflect our changes */
  1515.     
  1516.     trimRect->top -= trimOffTop;
  1517.     trimRect->bottom -= trimOffTop;
  1518.     trimRect->left -= trimOffLeft;
  1519.     trimRect->right -= trimOffLeft;
  1520.  
  1521.     /* return the new width and height in the image description and the size */
  1522.     
  1523.     (*desc)->height = newHeight;
  1524.     (*desc)->width = newWidth;
  1525.     (*desc)->dataSize = size;
  1526. bail:
  1527.     if ( progressProc ) 
  1528.         CallICMProgressProc(progressProc->progressProc,codecProgressClose,0,progressProc->progressRefCon);
  1529.  
  1530.     return(result);
  1531.  
  1532.  
  1533. }
  1534. #endif // DECO_BUILD
  1535.     
  1536. #if NOASM        /* we could do this part in assembly for speed if we desired */
  1537.  
  1538. #if COMP_BUILD
  1539.  
  1540. #define    READPIXEL(n)                \
  1541.     l = *lp++;                        \
  1542.     r = (l>>16);                    \
  1543.     g = (l>>8);                        \
  1544.     b = l;                            \
  1545.     yt = (R_W*r + G_W*g + B_W*b);    \
  1546.     if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
  1547.     ys[n] = yt>>16;                    \
  1548.     y += yt;                        \
  1549.     u += r;                            \
  1550.     v += b;                        
  1551.  
  1552. #define    READPIXEL_TAB(n)                \
  1553.     l = *lp++;                        \
  1554.     r = (l>>16);                    \
  1555.     g = (l>>8);                        \
  1556.     b = l;                            \
  1557.     yt = (rwTable[r] + gwTable[g] + bwTable[b]);    \
  1558.     if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
  1559.     ys[n] = yt>>16;                    \
  1560.     y += yt;                        \
  1561.     u += r;                            \
  1562.     v += b;                        
  1563.  
  1564.  
  1565. pascal void
  1566. CompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
  1567. {
  1568.  
  1569.     register long    l,*lp = (long *)baseAddr;
  1570.     register unsigned char     r,g,b;
  1571.     unsigned char    ys[4];
  1572.     register long    y,yt;
  1573.     short    u,v;
  1574.     short    rowLongs = (rowBytes>>2);
  1575.         
  1576.         
  1577.     
  1578.     
  1579.     len++;
  1580.     len>>=1;
  1581.     
  1582.     if ( sg->rgbwTable && *sg->rgbwTable  ) {
  1583.         long    *rwTable,*gwTable,*bwTable;
  1584.     
  1585.         rwTable = (long *)*sg->rgbwTable;
  1586.         gwTable = rwTable + 256;
  1587.         bwTable = rwTable + 512;
  1588.  
  1589.         while ( len-- > 0) {
  1590.             y = u = v = 0;
  1591.             READPIXEL_TAB(0);
  1592.             READPIXEL_TAB(1);
  1593.             lp += rowLongs-2;
  1594.             READPIXEL_TAB(2);
  1595.             READPIXEL_TAB(3);
  1596.             lp -= rowLongs;
  1597.         
  1598.             y >>= 16;
  1599.             u = (u - y)>>4;
  1600.             v = (v - y)>>4;
  1601.             
  1602.             l =  (long)(0xfc & (ys[0])) << 24;
  1603.             l |= (long)(0xfc & (ys[1])) << 18;
  1604.             l |= (long)(0xfc & (ys[2])) << 12;
  1605.             l |= (long)(0xfc & (ys[3])) <<  6;
  1606.             l |= u & 0xff;
  1607.             *(long *)data = MyEndian32(l);
  1608.             data += sizeof(long);
  1609.             *data++ = v;
  1610.         }
  1611.     } else {
  1612.         while ( len-- > 0) {
  1613.             y = u = v = 0;
  1614.             READPIXEL(0);
  1615.             READPIXEL(1);
  1616.             lp += rowLongs-2;
  1617.             READPIXEL(2);
  1618.             READPIXEL(3);
  1619.             lp -= rowLongs;
  1620.         
  1621.             y >>= 16;
  1622.             u = (u - y)>>4;
  1623.             v = (v - y)>>4;
  1624.             
  1625.             l =  (long)(0xfc & (ys[0])) << 24;
  1626.             l |= (long)(0xfc & (ys[1])) << 18;
  1627.             l |= (long)(0xfc & (ys[2])) << 12;
  1628.             l |= (long)(0xfc & (ys[3])) <<  6;
  1629.             l |= u & 0xff;
  1630.             *(long *)data = MyEndian32(l);
  1631.             data += sizeof(long);
  1632.             *data++ = v;
  1633.         }
  1634.     }
  1635. }
  1636.  
  1637. #endif // COMP_BUILD
  1638.  
  1639. #if DECO_BUILD
  1640. #define    WRITEPIXEL                \
  1641.     r = PIN(u+y);                \
  1642.     b = PIN(v+y);                \
  1643.     y <<= 16;                    \
  1644.     y -= r * R_W;                \
  1645.     y -= b * B_W;                \
  1646.     g = PIN(y / G_W);            \
  1647.     *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;    
  1648.  
  1649. #define    WRITEPIXEL_TAB            \
  1650.     r = PIN(u+y);                \
  1651.     b = PIN(v+y);                \
  1652.     y <<= 16;                    \
  1653.     y -= rwTable[r];        \
  1654.     y -= bwTable[b];        \
  1655.     g = giwTable[PIN(y>>16)];    \
  1656.     *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;    
  1657.     
  1658. pascal void
  1659. DecompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
  1660. {
  1661.     register long    y;
  1662.     register unsigned char     r,g,b;
  1663.     register long    l,*lp;
  1664.     long     u,v;
  1665.     unsigned char    ys[4];
  1666.     short    rowLongs = (rowBytes>>2);
  1667.     short    blen = len;
  1668.  
  1669.     lp = (long *)baseAddr;
  1670.     blen++;
  1671.     blen >>= 1;
  1672.     
  1673.     if ( sg->rgbwTable && *sg->rgbwTable &&  sg->giwTable && *sg->giwTable ) {
  1674.         unsigned char    *giwTable;    
  1675.         long    *rwTable,*bwTable;
  1676.  
  1677.         giwTable = (unsigned char *)(*sg->giwTable);
  1678.         rwTable = (long *)*sg->rgbwTable;
  1679.         bwTable = rwTable + 512;
  1680.         while ( blen-- > 0 ) {
  1681.             l = MyEndian32(*(long *)data);
  1682.             data += sizeof(long);
  1683.             ys[0] = (0xfc & (l>>24));
  1684.             ys[1] = (0xfc & (l>>18));
  1685.             ys[2] = (0xfc & (l>>12));
  1686.             ys[3] = (0xfc & (l>>6));
  1687.             u = (char)l;
  1688.             v = *data++;
  1689.             u<<=2;
  1690.             v<<=2;
  1691.             y = ys[0];
  1692.             WRITEPIXEL_TAB;
  1693.             y = ys[1];
  1694.             WRITEPIXEL_TAB;
  1695.             lp += rowLongs - 2;
  1696.             y = ys[2];
  1697.             WRITEPIXEL_TAB;
  1698.             y = ys[3];
  1699.             WRITEPIXEL_TAB;
  1700.             lp -= rowLongs;
  1701.         }
  1702.     } else {
  1703.         while ( blen-- > 0 ) {
  1704.             l = MyEndian32(*(long *)data);
  1705.             data += sizeof(long);
  1706.             ys[0] = (0xfc & (l>>24));
  1707.             ys[1] = (0xfc & (l>>18));
  1708.             ys[2] = (0xfc & (l>>12));
  1709.             ys[3] = (0xfc & (l>>6));
  1710.             u = (char)l;
  1711.             v = *data++;
  1712.             u<<=2;
  1713.             v<<=2;
  1714.             y = ys[0];
  1715.             WRITEPIXEL;
  1716.             y = ys[1];
  1717.             WRITEPIXEL;
  1718.             lp += rowLongs - 2;
  1719.             y = ys[2];
  1720.             WRITEPIXEL;
  1721.             y = ys[3];
  1722.             WRITEPIXEL;
  1723.             lp -= rowLongs;
  1724.         }
  1725.     }
  1726. }
  1727.  
  1728. #endif // DECO_BUILD
  1729.  
  1730. #endif // NOASM
  1731.  
  1732.  
  1733. #ifdef LINK_EXAMPLE_CODEC
  1734.  
  1735. void InstallExampleCodec(void);
  1736. void InstallExampleCodec(void)
  1737.  
  1738. {
  1739.  
  1740.     ComponentDescription td;
  1741.     Component    c;
  1742.     Handle    cname;
  1743.     Handle    dname;
  1744.  
  1745. #if COMP_BUILD
  1746.     cname = NewHandle(13);
  1747.     td.componentType = OSTypeConst('imco');
  1748.     td.componentSubType = OSTypeConst('exmp');
  1749.     td.componentManufacturer = OSTypeConst('appl');
  1750.     td.componentFlags = codecInfoDoes32;
  1751.     td.componentFlagsMask = 0;
  1752.     
  1753.     BlockMoveData("\pTEST EX COMP",*cname,13);
  1754.     if ((c= RegisterComponent(&td,NewComponentRoutineProc(EXAMPLECODEC), 0,cname,nil, nil)) == 0 ) {
  1755.         Debugger();
  1756.         ExitToShell();
  1757.     }
  1758.     SetDefaultComponent(c,defaultComponentAnyManufacturer+defaultComponentAnyFlags);
  1759. #endif
  1760.  
  1761. #if DECO_BUILD
  1762.     dname = NewHandle(13);
  1763.     td.componentType = OSTypeConst('imdc');
  1764.     td.componentSubType = OSTypeConst('exmp');
  1765.     td.componentManufacturer = OSTypeConst('appl');
  1766.     td.componentFlags = codecInfoDoes32;
  1767.     td.componentFlagsMask = 0;
  1768.  
  1769.     BlockMoveData("\pTEST EX DECO",*dname,13);
  1770.     if ((c= RegisterComponent(&td,NewComponentRoutineProc(EXAMPLECODEC), 0,dname,nil, nil)) == 0 ) {
  1771.         Debugger();
  1772.         ExitToShell();
  1773.     }
  1774.     SetDefaultComponent(c,defaultComponentAnyManufacturer+defaultComponentAnyFlags);
  1775. #endif
  1776. }
  1777. #endif
  1778.  
  1779. #if QT_MP && ASYNC_DECODE
  1780.  
  1781. Boolean TestBusy( Globals *glob )
  1782. {
  1783.     ComponentMPWorkFunctionHeaderRecord work;
  1784.  
  1785.     // give the MP stuff a chance to call completion routines, schedule, and whatever
  1786.     work.headerSize = sizeof(ComponentMPWorkFunctionHeaderRecord);
  1787.     work.recordSize = sizeof(ComponentMPWorkFunctionHeaderRecord);
  1788.     work.isRunning = false;
  1789.     work.workFlags = mpWorkFlagGetIsRunning;
  1790.  
  1791.     if (glob->decompressFunction)
  1792.         CallComponentMPWorkFunctionProc(glob->decompressFunction, glob->decompressFunctionRefCon, &work);
  1793.  
  1794.     return glob->decompressCount != 0;
  1795. }
  1796.  
  1797. #endif
  1798.